import { expect } from '@jest/globals';
import * as compressing from 'compressing';
import fsExtra from 'fs-extra';
import fs from 'fs-extra';
import path from 'path';

import { initExecuteCommand, runHvigorAsync } from '../../common/common';
import {
  AbilityType,
  APIType,
  APIVersion,
  CaseLevel,
  IsEnable,
  LanguageType,
  ModuleTemplateType,
  RuntimeOSType,
  SDKType,
  SignType,
} from '../../plugins/project-builder/models/constants';
import { TestCaseBuilder } from '../../plugins/task-builder/task-case-builder';
import { ProjectBuildOption, TestCaseFun } from '../../plugins/task-builder/test-case';
import { TestTaskOption } from '../../plugins/task-builder/test-task-option';

const projectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  }
};

const taskConfig: TestTaskOption = {
  caseLevel: CaseLevel.L1,
  sign: SignType.NoSign,
  ohpmInstall: IsEnable.Enable
};

const WorkerData = `import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker';

const workerPort: ThreadWorkerGlobalScope = worker.workerPort;

/**
 * Defines the event handler to be called when the worker thread receives a message sent by the host thread.
 * The event handler is executed in the worker thread.
 *
 * @param e message data
 */
workerPort.onmessage = function (e: MessageEvents) {
}

/**
 * Defines the event handler to be called when the worker receives a message that cannot be deserialized.
 * The event handler is executed in the worker thread.
 *
 * @param e message data
 */
workerPort.onmessageerror = function (e: MessageEvents) {
}

/**
 * Defines the event handler to be called when an exception occurs during worker execution.
 * The event handler is executed in the worker thread.
 *
 * @param e error message
 */
workerPort.onerror = function (e: ErrorEvent) {
}`;

const testFun: (module?: string) => TestCaseFun = (module?: string) => async (project, taskConfig, record) => {
  // 工程主目录
  const projectRoot = project.projectRootPath();

  // 拼接命令行
  const commands = initExecuteCommand({
    mode: 'module',
    product: 'default',
    tasks: 'assembleHap'
    , ...(module ? { module: `${module}@default` } : {})
  });
  const result = await runHvigorAsync(projectRoot, commands);

  record.addStep(`${module} 模块首次编译`, result);
  expect(result.stdout).toContain('BUILD SUCCESSFUL');

  const entryModulePath = project.getModule('entry').moduleRootPath();
  await fs.mkdir(path.resolve(entryModulePath, 'src/main/ets/workers'));
  await fs.writeFile(path.resolve(entryModulePath, 'src/main/ets/workers/Worker.ts'), WorkerData);

  const result2 = await runHvigorAsync(projectRoot, commands);
  record.addStep(`${module} 模块二次编译`, result2);

  await fsExtra.copyFile(path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned.hap'),
    path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned.zip'));
  await compressing.zip.uncompress(
    path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned.zip'),
    path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned'));
  const sourceMapsData = await fsExtra.readFile(path.resolve(project.getModule('entry').moduleRootPath(), 'build/default/outputs/default/entry-default-unsigned/ets/sourceMaps.map'), 'utf-8');
  const isBoolWorker = sourceMapsData.includes('entry/src/main/ets/workers/Worker.ts');
  expect(isBoolWorker).toBe(true);
  expect(result2.stdout).toContain('BUILD SUCCESSFUL');

  const result3 = await runHvigorAsync(projectRoot, commands);
  record.addStep(`${module} 修改文件增量编译`, result3);
  await fs.writeFile(path.resolve(entryModulePath, 'src/main/ets/workers/Worker.ts'), '');
  await fsExtra.copyFile(path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned.hap'),
    path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned.zip'));
  await compressing.zip.uncompress(
    path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned.zip'),
    path.resolve(entryModulePath, 'build/default/outputs/default/entry-default-unsigned'));
  const sourceMapsToData = await fsExtra.readFile(path.resolve(project.getModule('entry').moduleRootPath(), 'build/default/outputs/default/entry-default-unsigned/ets/sourceMaps.map'), 'utf-8');
  const isBoolToWorker = sourceMapsToData.includes('entry/src/main/ets/workers/Worker.ts');
  expect(isBoolToWorker).toBe(true);
  expect(result3.stdout).toContain('BUILD SUCCESSFUL');
};

TestCaseBuilder.builder()
  .caseName('OPENLAB_AIDE_ZOS_Build_Incremental_Compilation_api10_FA_Ets_Open_Update_007')
  .description('增量编译-修改ability进行增量编译校验')
  .projectBuilderOption(projectBuilderOption)
  .taskConfig(taskConfig)
  .testFun(testFun('entry'))
  .load();
